﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Caifu.Clients;
using Caifu.Datas;
using Caifu.Pres;
using Caifu.Pres.Datas;

namespace Caifu.Spiders
{
	/// <summary>
	/// 核对服务
	/// </summary>
	public class CheckService
	{
		// 最后一次运行核对的时间
		private static DateTime m_LastCheckTime = DateTime.MinValue;
		// 两次核对之间的最小间隔
		private static TimeSpan m_MinInterval = new TimeSpan(0, 0, 30);

		public static void Run()
		{
			// 期望日期
			DateTime date;
			if (!DateUtil.NowIsCheckTime(out date))
			{
				return;
			}

			if (DateTime.Now - m_LastCheckTime < m_MinInterval)
			{// 核对时间过短
				return;
			}

			RunCheck(date);
		}

		/// <summary>
		/// 运行智能核对
		/// </summary>
		/// <param name="date"></param>
		public static void RunCheck(DateTime date)
		{
			var dataSource = NetValuePreData.Instance.GetNetValuePres(date, 1, Int32.MaxValue);

			foreach (var item in dataSource)
			{
				// 排除前一次3家都对上的记录
				if (item.CheckStatus >= 3) continue;

				int checkStatus = 0;
				decimal unitNetValue = 0, accumulatedNetValue = 0;

				bool exist1, exist2, exist3;
				CheckExists(item, out exist1, out exist2, out exist3);
				bool equal_12 = IsEquals(item.UnitNetValue1, item.AccumulatedNetValue1, item.UnitNetValue2, item.AccumulatedNetValue2);
				bool equal_13 = IsEquals(item.UnitNetValue1, item.AccumulatedNetValue1, item.UnitNetValue3, item.AccumulatedNetValue3);
				bool equal_23 = IsEquals(item.UnitNetValue2, item.AccumulatedNetValue3, item.UnitNetValue3, item.AccumulatedNetValue3);

				#region 对比数据，确定状态

				if (exist1)
				{
					checkStatus = 1;
					unitNetValue = item.UnitNetValue1.Value;
					accumulatedNetValue = item.AccumulatedNetValue1.Value;
					if (exist2)
					{
						if (equal_12)
						{// 第1组和第2组核对上
							checkStatus += 1;
							if (exist3)
							{
								if (equal_13)
								{// 第1组和第3组核对上
									checkStatus += 1;
								}
								else
								{// 对不上
									checkStatus = -1;
								}
							}
						}
						else
						{// 对不上
							checkStatus = -1;
						}
					}
					else if (exist3)
					{
						if (equal_13)
						{// 第1组和第3组核对上
							checkStatus += 1;
						}
						else
						{// 对不上
							checkStatus = -1;
						}
					}
				}
				else if (exist2)
				{
					checkStatus = 1;
					unitNetValue = item.UnitNetValue2.Value;
					accumulatedNetValue = item.AccumulatedNetValue2.Value;
					if (exist3)
					{
						if (equal_23)
						{
							checkStatus = 2;
						}
						else
						{
							checkStatus = -1;
						}
					}
				}
				else if (exist3)
				{
					checkStatus = 1;
					unitNetValue = item.UnitNetValue3.Value;
					accumulatedNetValue = item.AccumulatedNetValue3.Value;
				}

				if (exist1 && exist2 && exist3)
				{// 全部采到，但各不相等
					if (!equal_12 && !equal_13 && !equal_23)
					{
						checkStatus = -3;
					}
				}

				#endregion

				#region 更新净值数据

				var fund = FundClient.GetFund(item.FundCode);
				if (fund == null)
				{
					// 报告问题，可能基金代码不能对上，可能缺少基金
					continue;
				}
				var fundNetValue = NetValueData.Instance.GetNetValue(fund.Id, date);
				bool existsFundNetValue = true;
				if (fundNetValue == null)
				{
					existsFundNetValue = false;
					fundNetValue = new NetValue();
					fundNetValue.FundId = fund.Id;
					fundNetValue.ReportDate = date;
				}
				if (fundNetValue.UnitNetValue != unitNetValue || fundNetValue.AccumulatedNetValue != accumulatedNetValue)
				{// 当净值表中的数据与刚核对完的数据不一致时，需要更新净值表
					fundNetValue.UnitNetValue = unitNetValue;
					fundNetValue.AccumulatedNetValue = accumulatedNetValue;

					if (existsFundNetValue)
					{
						NetValueClient.UpdateNetValue(fundNetValue);
					}
					else
					{
						NetValueClient.AddNetValue(fundNetValue);
					}
				}

				#endregion

				#region 更新核对结果

				if (checkStatus != item.CheckStatus || item.UnitNetValue != unitNetValue || item.AccumulatedNetValue != accumulatedNetValue)
				{
					item.UnitNetValue = unitNetValue;
					item.AccumulatedNetValue = accumulatedNetValue;
					item.CheckStatus = checkStatus;

					item.FundId = fund.Id;

					NetValuePreData.Instance.UpdateNetValuePre(item);
				}

				#endregion
			}
		}

		private static bool IsExists(decimal? unav, decimal? anav)
		{
			return unav > 0 && anav > 0;
		}

		private static bool IsEquals(decimal? unav1, decimal? anav1, decimal? unav2, decimal? anav2)
		{
			if (unav1.HasValue && anav1.HasValue
				& unav2.HasValue && anav2.HasValue)
			{
				return unav1 == unav2 && anav1 == anav2;
			}
			else
			{
				return false;
			}
		}

		private static void CheckExists(NetValuePre netValuePre, out bool exist1, out bool exist2, out bool exist3)
		{
			exist1 = exist2 = exist3 = false;

			if (netValuePre.UnitNetValue1 > 0 && netValuePre.AccumulatedNetValue1 > 0)
			{
				exist1 = true;
			}
			if (netValuePre.UnitNetValue2 > 0 && netValuePre.AccumulatedNetValue2 > 0)
			{
				exist2 = true;
			}
			if (netValuePre.UnitNetValue3 > 0 && netValuePre.AccumulatedNetValue3 > 0)
			{
				exist3 = true;
			}
		}

		private static void CheckExists(PreNetValueCheck item, out bool exist1, out bool exist2, out bool exist3)
		{
			exist1 = exist2 = exist3 = false;

			if (item.UnitNetValue1 > 0 && item.AccumulatedNetValue1 > 0)
			{
				exist1 = true;
			}
			if (item.UnitNetValue2 > 0 && item.AccumulatedNetValue2 > 0)
			{
				exist2 = true;
			}
			if (item.UnitNetValue3 > 0 && item.AccumulatedNetValue3 > 0)
			{
				exist3 = true;
			}
		}

		private static void CheckEquals(NetValuePre netValuePre, out bool equal12, out bool equal13, out bool equal23)
		{
			equal12 = equal13 = equal23 = false;
		}

		/// <summary>
		/// 组装净值核对条目
		/// </summary>
		/// <param name="date"></param>
		/// <returns></returns>
		public static IList<PreNetValueCheck> _AssemblyCheckEnties(DateTime date)
		{
			var list1 = PreNetValueThirdData.Instance.List(date, "和讯网");
			var list2 = PreNetValueThirdData.Instance.List(date, "金融界");
			var list3 = PreNetValueThirdData.Instance.List(date, "易天富");
			var dict1 = list1.ToDictionary(p => p.FundCode, p => p);
			var dict2 = list2.ToDictionary(p => p.FundCode, p => p);
			var dict3 = list3.ToDictionary(p => p.FundCode, p => p);
			var fundCodeList1 = list1.Select(p => p.FundCode).ToList();
			var fundCodeList2 = list2.Select(p => p.FundCode).ToList();
			var fundCodeList3 = list3.Select(p => p.FundCode).ToList();
			var fundCodes = fundCodeList1.Union(fundCodeList2).Union(fundCodeList3);

			List<PreNetValueCheck> preNetValueChecks = new List<PreNetValueCheck>();

			foreach (var fundCode in fundCodes)
			{
				PreNetValueCheck preNetValueCheck = new PreNetValueCheck();
				preNetValueCheck.FundCode = fundCode;
				preNetValueCheck.ReportDate = date;

				PreNetValueThird preNetValueThird1;
				if (dict1.TryGetValue(fundCode, out preNetValueThird1))
				{
					preNetValueCheck.UnitNetValue1 = preNetValueThird1.UnitNetValue;
					preNetValueCheck.AccumulatedNetValue1 = preNetValueThird1.AccumulatedNetValue;
				}

				PreNetValueThird preNetValueThird2;
				if (dict2.TryGetValue(fundCode, out preNetValueThird2))
				{
					preNetValueCheck.UnitNetValue2 = preNetValueThird2.UnitNetValue;
					preNetValueCheck.AccumulatedNetValue2 = preNetValueThird2.AccumulatedNetValue;
				}

				PreNetValueThird preNetValueThird3;
				if (dict3.TryGetValue(fundCode, out preNetValueThird3))
				{
					preNetValueCheck.UnitNetValue3 = preNetValueThird3.UnitNetValue;
					preNetValueCheck.AccumulatedNetValue3 = preNetValueThird3.AccumulatedNetValue;
				}

				preNetValueChecks.Add(preNetValueCheck);
			}

			return preNetValueChecks;
		}

		public static void _Check(DateTime date)
		{
			#region 更新新的净值信息

			var newPreNetValueChecks = _AssemblyCheckEnties(date);
			var oldPreNetValueChecks = PreNetValueCheckData.Instance.List(date);
			var oldPreNetValueCheckDict = oldPreNetValueChecks.ToDictionary(p => p.FundCode, p => p);

			foreach (var newItem in newPreNetValueChecks)
			{
				PreNetValueCheck oldItem;
				if (oldPreNetValueCheckDict.TryGetValue(newItem.FundCode, out oldItem))
				{
					if (oldItem.UnitNetValue1 != newItem.UnitNetValue1 || oldItem.AccumulatedNetValue1 != newItem.AccumulatedNetValue1
						|| oldItem.UnitNetValue2 != newItem.UnitNetValue2 || oldItem.AccumulatedNetValue2 != newItem.AccumulatedNetValue2
						|| oldItem.UnitNetValue3 != newItem.UnitNetValue3 || oldItem.AccumulatedNetValue3 != newItem.AccumulatedNetValue3)
					{
						oldItem.UnitNetValue1 = newItem.UnitNetValue1;
						oldItem.AccumulatedNetValue1 = newItem.AccumulatedNetValue1;
						oldItem.UnitNetValue2 = newItem.UnitNetValue2;
						oldItem.AccumulatedNetValue2 = newItem.AccumulatedNetValue2;
						oldItem.UnitNetValue3 = newItem.UnitNetValue1;
						oldItem.AccumulatedNetValue3 = newItem.AccumulatedNetValue3;

						PreNetValueCheckData.Instance.Update(oldItem);
					}
				}
				else
				{
					PreNetValueCheckData.Instance.Add(newItem);
				}
			}

			#endregion

			var preNetValueChecks = PreNetValueCheckData.Instance.List(date);
			foreach (var item in preNetValueChecks)
			{
				// 排除前一次3家都对上的记录
				if (item.CheckStatus >= 3) continue;

				int checkStatus = 0;
				decimal unitNetValue = 0, accumulatedNetValue = 0;

				bool equal_12 = IsEquals(item.UnitNetValue1, item.AccumulatedNetValue1, item.UnitNetValue2, item.AccumulatedNetValue2);
				bool equal_13 = IsEquals(item.UnitNetValue1, item.AccumulatedNetValue1, item.UnitNetValue3, item.AccumulatedNetValue3);
				bool equal_23 = IsEquals(item.UnitNetValue2, item.AccumulatedNetValue3, item.UnitNetValue3, item.AccumulatedNetValue3);

				if (equal_12 && equal_13)
				{// 三者相等
					checkStatus = 3;
					unitNetValue = item.UnitNetValue1.Value;
					accumulatedNetValue = item.AccumulatedNetValue1.Value;
				}
				else if (equal_12 || equal_13)
				{
					checkStatus = 2;
					unitNetValue = item.UnitNetValue1.Value;
					accumulatedNetValue = item.AccumulatedNetValue1.Value;
				}
				else if (equal_23)
				{
					checkStatus = 2;
					unitNetValue = item.UnitNetValue2.Value;
					accumulatedNetValue = item.AccumulatedNetValue2.Value;
				}
				else
				{// 没有一组相等的情况下
					checkStatus = 0;
					bool exist1, exist2, exist3;
					CheckExists(item, out exist1, out exist2, out exist3);

					// 采纳任意存在的一个
					if (exist1)
					{
						checkStatus = 1;
						unitNetValue = item.UnitNetValue1.Value;
						accumulatedNetValue = item.AccumulatedNetValue1.Value;
					}
					else if (exist2)
					{
						checkStatus = 1;
						unitNetValue = item.UnitNetValue2.Value;
						accumulatedNetValue = item.AccumulatedNetValue2.Value;
					}
					else if (exist3)
					{
						checkStatus = 1;
						unitNetValue = item.UnitNetValue3.Value;
						accumulatedNetValue = item.AccumulatedNetValue3.Value;
					}
				}

				if (unitNetValue > 0 && accumulatedNetValue > 0)
				{
					#region 更新净值数据

					var fund = FundClient.GetFund(item.FundCode);
					if (fund == null)
					{
						// 报告问题，可能基金代码不能对上，可能缺少基金
						continue;
					}
					var fundNetValue = NetValueData.Instance.GetNetValue(fund.Id, date);
					bool existsFundNetValue = true;
					if (fundNetValue == null)
					{
						existsFundNetValue = false;
						fundNetValue = new NetValue();
						fundNetValue.FundId = fund.Id;
						fundNetValue.ReportDate = date;
					}
					if (fundNetValue.UnitNetValue != unitNetValue || fundNetValue.AccumulatedNetValue != accumulatedNetValue)
					{// 当净值表中的数据与刚核对完的数据不一致时，需要更新净值表
						fundNetValue.UnitNetValue = unitNetValue;
						fundNetValue.AccumulatedNetValue = accumulatedNetValue;

						if (existsFundNetValue)
						{
							NetValueClient.UpdateNetValue(fundNetValue);
						}
						else
						{
							NetValueClient.AddNetValue(fundNetValue);
						}
					}


					#endregion

					#region 更新核对结果

					if (checkStatus != item.CheckStatus
						|| item.UnitNetValue != unitNetValue
						|| item.AccumulatedNetValue != accumulatedNetValue)
					{
						item.UnitNetValue = unitNetValue;
						item.AccumulatedNetValue = accumulatedNetValue;
						item.CheckStatus = checkStatus;

						item.FundId = fund.Id;

						PreNetValueCheckData.Instance.Update(item);
					}

					#endregion
				}
			}
		}

		enum CompareResult
		{

		}
	}
}
